package org.finesys.common.tenant.filter;

import java.io.IOException;
import java.util.Objects;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.finesys.common.core.module.R;
import org.finesys.common.core.util.WebUtil;
import org.finesys.common.security.core.module.AuthUser;
import org.finesys.common.security.core.util.SecurityUtils;
import org.finesys.common.tenant.properties.TenantProperties;
import org.finesys.common.tenant.service.TenantValidService;
import org.finesys.common.tenant.support.TenantContextHolder;
import org.springframework.http.MediaType;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 用户租户信息合法性校验拦截器
 */
@Slf4j
public class TenantSecurityWebFilter extends OncePerRequestFilter {
    private final TenantProperties tenantProperties;
    private final TenantValidService tenantValidService;
    private final AntPathMatcher antPathMatcher;

    public TenantSecurityWebFilter(TenantProperties tenantProperties, TenantValidService tenantValidService) {
        this.tenantProperties = tenantProperties;
        this.tenantValidService = tenantValidService;
        this.antPathMatcher = new AntPathMatcher();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 线程上下文中存储的租户id
        Long tenantId = TenantContextHolder.getTenantId();
        if (!skipDispatch(request)) {
            // 当前url不放行且未带租户的编号 不允许访问
            if (Objects.isNull(tenantId)) {
                if (log.isInfoEnabled()) {
                    log.info("未传递租户编号");
                }
                WebUtil.makeResponse(response, MediaType.APPLICATION_JSON_VALUE, HttpServletResponse.SC_FORBIDDEN, R.failed("租户信息未传递"));
                return;
            }

            try {
                // 校验租户是否合法
                tenantValidService.validTenant(tenantId);
            } catch (Exception e) {
                WebUtil.makeResponse(response, MediaType.APPLICATION_JSON_VALUE, HttpServletResponse.SC_FORBIDDEN, R.failed(e.getMessage()));
                return;
            }
            AuthUser authUser = SecurityUtils.getUser();
            //还未授权
            if (Objects.isNull(authUser)) {
                filterChain.doFilter(request, response);
                return;
            }
            if (Objects.isNull(authUser.getTenantId()) || !Objects.equals(tenantId, authUser.getTenantId())) {
                WebUtil.makeResponse(response, MediaType.APPLICATION_JSON_VALUE, HttpServletResponse.SC_FORBIDDEN,
                        R.failed("无权访问该租户"));
                return;
            }

        } else {
            // 当前url放行且没携带租户id
            if (Objects.isNull(tenantId)) {
                TenantContextHolder.setIgnore(true);
            }
        }
        filterChain.doFilter(request, response);
    }

    /**
     * 当前访问路径是否放行
     *
     * @param request 当前请求
     * @return 是否放行
     */
    private boolean skipDispatch(HttpServletRequest request) {
        // Direct match or Pattern match
        String uri = request.getRequestURI();
        return CollUtil.contains(tenantProperties.getIgnoreUrls(), uri) || tenantProperties.getIgnoreUrls().stream().anyMatch(isIgnoreUrl -> antPathMatcher.match(isIgnoreUrl, request.getRequestURI()));
    }
}
